package com.boboPlanet.user.component;

import cn.hutool.core.bean.BeanUtil;
import cn.xuyanwu.spring.file.storage.FileInfo;
import cn.xuyanwu.spring.file.storage.FileStorageService;
import cn.xuyanwu.spring.file.storage.ProgressListener;
import com.boboPlanet.comm.entity.po.FileDetailPO;
import com.boboPlanet.comm.exception.BusinessException;
import com.boboPlanet.comm.feign.PlanetFileApi;
import com.boboPlanet.comm.result.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: TODO 星球文件流下载
 * @Author: mis_wu
 * @Date: 2023/7/8
 * @Company planet
 **/
@Component
@Slf4j
public class PlanetFileStreamDown {

    @Resource
    private FileStorageService fileStorageService;

    @Resource
    private PlanetFileApi planetFileApi;

    @Value("${spring.planet.file.upload.base-path}")
    private String basePath;

    private static final String SPLIT_STR_DIAN = ".";

    /**
     * 星球文件下载 二进制文件
     * @param fileName String 文件名称【加后缀】
     * @return Map<String,Object> 文件下载进度信息
     */
    public Map<String,Object> downloadFileWithBytes(String fileName, HttpServletResponse response) throws IOException {
        if (StringUtils.isBlank(fileName)){
            throw BusinessException.build("文件下载失败,文件名称不能为空,请重新选择");
        }
        String url = basePath + fileName;
        File file = new File(url);
        if (!file.exists()){
            throw BusinessException.build("文件下载失败,无效的下载地址【" + url + "】,请重新选择");
        }
        FileDetailPO dbFile = this.getFileInfo(fileName);
        FileInfo fileInfo =  BeanUtil.copyProperties(dbFile,FileInfo.class,"attr");
        //FileInfo fileInfo = fileStorageService.getFileInfoByUrl(file.getPath());
        if (fileInfo == null){
            throw BusinessException.build("文件下载失败,无效的下载地址【" + url + "】,请重新选择");
        }

        Map<String,Object> map = new HashMap<>(4);
        //监听下载进度
        byte[] bytes = fileStorageService.download(fileInfo).setProgressMonitor(new ProgressListener() {
            @Override
            public void start() {
                log.info("file start download,please waiting");
            }

            @Override
            public void progress(long progressSize,long allSize) {
                map.put("progressSize",progressSize);
                map.put("allSize",allSize);
                map.put("downProgress",false);
                log.info("file is downloading,please waiting");
            }

            @Override
            public void finish() {
                map.put("downProgress",true);
                log.info("file is downloaded success");
            }
        }).bytes();
        //todo 用websocket发送进度map

        response.reset();
        response.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode(fileInfo.getFilename(), StandardCharsets.UTF_8.name()));
        response.addHeader("Content-Length","" + bytes.length);
        response.setContentType("application/octet-stream;charset=UTF-8");
        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();

        return map;
    }

    /**
     * 文件下载，下载到文件流
     * @param fileName String 文件全路径【加后缀】
     */
    public void downloadFileWithStream(String fileName,HttpServletResponse response) throws Exception {
        FileDetailPO detail = getFileInfo(fileName);

        FileInfo fileInfo = BeanUtil.copyProperties(detail,FileInfo.class,"attr");
        if (fileInfo == null){
            throw BusinessException.build("文件下载失败,请确认文件是否存在,请重新选择");
        }

        response.setContentType(fileInfo.getContentType());
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileInfo.getFilename(), "UTF-8"));
        response.setHeader("Content-Length", String.valueOf(fileInfo.getSize()));

        File file = new File(fileInfo.getUrl());
        InputStream fileInputStream = Files.newInputStream(file.toPath());
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fileInputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }

            response.flushBuffer();
        } catch (IOException e) {
            throw new IOException("Failed to download file " + fileName, e);
        } finally {
            fileInputStream.close();
            assert outputStream != null;
            outputStream.close();
        }

        //下载到 OutputStream 中
//        ByteArrayOutputStream out = new ByteArrayOutputStream();
//        byte[] buffer = new byte[1024];
//        int len;
//        while ((len = fileInputStream.read(buffer)) > 0) {
//            out.write(buffer, 0, len);
//        }
//
//        fileStorageService.download(fileInfo).outputStream(out);

    }

    /**
     * todo:废弃不用 不推荐
     * 下载到指定文件
     * @param fileName String 文件名称
     * @param target  String 目标文件地址
     */
    @Deprecated
    public void downloadFileWithFile(String fileName,String target) {
        FileDetailPO detail = getFileInfo(fileName);
        String suffix = fileName.substring(fileName.lastIndexOf(SPLIT_STR_DIAN));
        if (StringUtils.isBlank(target)){
            target = "C://planet" + System.currentTimeMillis() + suffix;
        }
        detail.setUrl(target);

        FileInfo file = BeanUtil.copyProperties(detail,FileInfo.class,"attr");

        //下载到文件
        fileStorageService.download(file).file(target);

    }


    /**
     * 原生springboot下载
     * @param fileName 文件名称[加后缀]
     * @param response HttpServletResponse
     * @throws IOException E
     */
    public void download(String fileName,HttpServletResponse response) throws IOException {
        String filePath = basePath + fileName;
        File file = new File(filePath);
        String originFileName = file.getName();
        String ext = fileName.substring(originFileName.lastIndexOf(".") + 1).toLowerCase();
        log.info("download file,ext is:{}",ext);
        FileInputStream fileInputStream = new FileInputStream(file);
        InputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        byte[] bytes = new byte[bufferedInputStream.available()];
        int read = bufferedInputStream.read(bytes);
        log.info("download file,read byte is:{}",read);
        bufferedInputStream.close();

        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(originFileName,"UTF-8"));
        response.addHeader("Content-Length","" + file.length());

        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        response.setContentType("application/octet-stream");
        outputStream.write(bytes);
        outputStream.flush();
    }

    /**
     * 根据文件 URL获取文件信息
     * @param fileName 文件名称
     * @return String文件地址
     */
    private FileDetailPO getFileInfo(String fileName){
        if (StringUtils.isBlank(fileName)){
            throw BusinessException.build("文件下载失败,文件名称不能为空,请重新选择");
        }
        String url = basePath + fileName;

        ResponseResult<FileDetailPO> urlResult = planetFileApi.getFileByUrl(url);
        if (urlResult == null || urlResult.getData() == null || StringUtils.isBlank(urlResult.getData().getUrl())){
            throw BusinessException.build("文件下载失败,无效的下载地址【" + url + "】,请重新选择");
        }
        return urlResult.getData();
    }

}
